using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace Tarea4
{
    partial class ViewGUI : Form, ViewInterface, ObserverInterface
    {
        private bool initialized;
        private TableLayoutPanel tablero;
        private Button[] tiles;
        //private short[,] initialBoard;
        private int Row;
        private int Col;
        private ControllerInterface controller;
        private ModelInterface model;

        public ViewGUI()
        {
            InitializeComponent();
            Form.CheckForIllegalCrossThreadCalls = false;
        }

        #region Model Controller Integration
        /// <summary>
        /// Model Controller Integration Methods
        /// </summary>

        public void Initialize(string title, ControllerInterface controller)
        {
            this.controller = controller;
            this.Text = title;
            this.cmbModel.SelectedIndex = 0;
            this.cmbSize.SelectedIndex = 0;
            initialized = true;
            selectBehavior();
            Application.Run((Form)this);
        }

        public void SetModel(string title, ModelInterface model)
        {

            if (this.model != null)
                model.RemoveObserver(this);

            this.model = model;
            this.Text = title;

            model.RegisterObserver(this);

            int n = model.InitialBoard.GetLength(0);
            buildBoard(n);
            addTiles(model.InitialBoard);
        }

        public void Update(StateInterface state, string msg, string info)
        {
            updateTiles(state.Board);
            lblMessage.Text = (msg.Length == 0 ? "" : msg + "\n") + info;
        }

        private void selectBehavior()
        {
            if (!initialized)
                return;

            //Win.Visible = false;

            Behaviors.Behavior behavior = Behaviors.Behavior.NNPINT;

            switch (cmbModel.SelectedIndex)
            {
                case 0:
                    behavior = Behaviors.Behavior.NNPINT;
                    tbSpeed.Enabled = false;
                    btnPause.Enabled = false;
                    btnStart.Enabled = false;
                    btnUndo.Enabled = true;
                    break;
                case 1:
                    behavior = Behaviors.Behavior.NNPAST;
                    tbSpeed.Enabled = true;
                    btnPause.Enabled = true;
                    btnStart.Enabled = true;
                    btnUndo.Enabled = false;
                    break;
            }

            short[,]tmp;
            while (!IsValid((tmp = GenerateInitialBoard())));
            controller.SetModel(behavior, tbSpeed.Value, tmp);
        }

        public bool IsValid(short[,] b)
        {
            int counter = 0;
            int value = 0;
            int blank = 0;
            for (int i = 0; i < b.GetLength(0); i++)
                for(int j = 0; j < b.GetLength(0); j++)
                {
                    if (b[i, j] == 0)
                    {
                        blank = i + 1;
                        continue;
                    }
                    else
                        value = b[i, j];

                    bool flag = true;
                    for (int k = i; k < b.GetLength(0); k++)
                        for (int l = (flag  ? j : 0); l < b.GetLength(0); l++)
                        {
                            flag = false;
                            if (value > b[k, l] && b[k, l] != 0)
                                counter++;
                        }
                }
            
            Console.WriteLine("PARITY: " + counter + " " + "Blank: " + blank);
            
            if (b.GetLength(0) == 4)
                return (counter + blank) % 2 == 0;
            else
                return counter % 2 == 0;

            return false;
        }

        private short[,] GenerateInitialBoard()
        {
            Random rand = new Random();
            int size = Int16.Parse(cmbSize.Text);
            int pos = 0;
            short[] numbers = new short[size*size];
            short[,] initialBoard = new short[size, size];
            //short[,] initialBoard = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 0 } };//new short[size,size];
            //short[,] initialBoard = { { 4, 1, 3 }, { 2, 6, 0 }, { 7, 5, 8 } };//new short[size,size];
            //short[,] initialBoard = { { 7, 4, 3 }, { 1, 0, 2 }, { 8, 6, 5 } };//new short[size,size];
            //short[,] initialBoard = { { 4, 3, 6 }, { 2, 1, 8 }, { 7, 5, 0 } };//new short[size,size];
            //short[,] initialBoard = { { 2, 3, 6 }, { 1, 5, 8 }, { 4, 7, 0 } };//new short[size,size];
            //short[,] initialBoard = { { 2, 4, 3 }, { 1, 8, 5 }, { 0, 7, 6 } };//new short[size,size];
            //short[,] initialBoard = { { 4, 1, 3 }, { 2, 6, 0 }, { 7, 5, 8 } };//new short[size,size];
            //short[,] initialBoard = { { 7, 8, 4 }, { 5, 6, 2 }, { 0, 1, 3 } };//new short[size,size];
            //short[,] initialBoard = { { 1, 2, 3 }, { 4, 6, 8 }, { 7, 0, 5 } };//new short[size,size];
            //short[,] initialBoard = { { 1, 5, 2 }, { 7, 4, 3 }, { 8, 0, 6 } };//new short[size,size];
            //short[,] initialBoard = { { 1, 3, 5 }, { 4, 2, 0 }, { 7, 8, 6 } };//new short[size,size];
            //short[,] initialBoard = { { 4, 3, 6 }, { 1, 0, 2 }, { 7, 5, 8 } };//new short[size,size];
            //short[,] initialBoard = { { 4, 1, 3 }, { 7, 0, 5 }, { 8, 2, 6 } };//new short[size,size];
            //short[,] initialBoard = { { 2, 3,5  }, { 1, 4, 0 }, { 7, 8, 6 } };//new short[size,size];
            //short[,] initialBoard = { { 4, 1, 3 }, { 7, 2, 5 }, { 0, 8, 6 } };//new short[size,size];
            /*short[,] initialBoard = { { 1, 7, 2, 4, 5 }, 
                                      { 11, 6, 3, 8, 10 },
                                      { 16, 12, 13, 9, 15 },
                                      { 21, 18, 23, 14, 0 },
                                      { 22, 17, 19, 24, 20 } };//new short[size,size];*/
            /*short[,] initialBoard = { { 1, 7, 2, 4, 5 }, 
                                      { 11, 6, 3, 8, 10 },
                                      { 16, 12, 13, 9, 0 },
                                      { 21, 18, 23, 14, 15 },
                                      { 22, 17, 19, 24, 20 } };//new short[size,size];*/
            /*short[,] initialBoard = { { 1, 7, 2, 0, 5 }, 
                                      { 11, 6, 3, 4, 10 },
                                      { 16, 12, 13, 8, 9 },
                                      { 21, 18, 23, 14, 15 },
                                      { 22, 17, 19, 24, 20 } };//new short[size,size];*/
            /*short[,] initialBoard = { { 1, 0, 7, 2, 5 }, 
                                      { 11, 6, 3, 4, 10 },
                                      { 16, 12, 13, 8, 9 },
                                      { 21, 18, 23, 14, 15 },
                                      { 22, 17, 19, 24, 20 } };//new short[size,size];*/
            /*short[,] initialBoard = { { 1, 6, 7, 2, 5 }, 
                                      { 16, 11, 3, 4, 10 },
                                      { 0, 12, 13, 8, 9 },
                                      { 21, 18, 23, 14, 15 },
                                      { 22, 17, 19, 24, 20 } };//new short[size,size];*/
            /*short[,] initialBoard = { { 1, 6, 7, 2, 5 }, 
                                      { 0, 11, 3, 4, 10 },
                                      { 16, 12, 13, 8, 9 },
                                      { 21, 18, 23, 14, 15 },
                                      { 22, 17, 19, 24, 20 } };//new short[size,size];*/
        


            //return initialBoard;

            for(int i = 0; i < size*size; i++)
                numbers[i] = (short)i;

            for (int i = 0; i < initialBoard.GetLength(0); i++)
                for (int j = 0; j < initialBoard.GetLength(1); j++)
                {
                    pos = (pos + rand.Next(size * size)) % (size * size);
                    while(numbers[pos] == -1) pos = (pos + 1) % (size * size);
                    initialBoard[i,j] = numbers[pos];
                    numbers[pos] = -1;
                }

            return initialBoard;
        }

        //
        #endregion
        //
        #region Form Components
        /// <summary>
        /// ViewGUI Components Format
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>

        public void buildBoard(int size)
        {
            tablero = new TableLayoutPanel();
            tablero.Hide();
            this.tablero.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
            | System.Windows.Forms.AnchorStyles.Left)
            | System.Windows.Forms.AnchorStyles.Right)));
            this.tablero.AutoSize = false;
            this.tablero.CellBorderStyle = System.Windows.Forms.TableLayoutPanelCellBorderStyle.Inset;
            this.tablero.ColumnCount = size;
            for (int i = 0; i < tablero.ColumnCount; i++)
            {
                this.tablero.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, ((tablero.Width / size) * 100) / tablero.Width));
            }
            this.tablero.Location = new System.Drawing.Point(55, 3);
            this.tablero.Name = "tablero";
            this.tablero.RowCount = size;
            for (int i = 0; i < tablero.ColumnCount; i++)
            {
                this.tablero.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, ((tablero.Height / size) * 100) / tablero.Width));
            }
            this.tablero.Size = new System.Drawing.Size(485, 485);
            this.tablero.TabIndex = 0;
            this.splitContainer1.Panel2.Controls.Clear();
            this.splitContainer1.Panel2.Controls.Add(tablero);
        }

        public void tiles_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < tiles.Length; i++)
            {
                if (sender.Equals(tiles[i]))
                {
                    Row = i / Convert.ToInt16(cmbSize.SelectedItem);
                    Col = i % Convert.ToInt16(cmbSize.SelectedItem);
                }
            }

            controller.MoveCell(Row, Col);
        }

        public void addTiles(short [,] board)
        {
            tablero.Hide();
            tablero.Controls.Clear();

            int size = board.GetLength(0);
            int k = 0;

            tiles = new Button[size * size];

            for (int i = 0; i < size; i++)
                for(int j = 0; j < size; j++)
                {
                    tiles[k] = new Button();
                    tiles[k].Click += new System.EventHandler(tiles_Click);
                    /// format button
                    tiles[k].BackColor = System.Drawing.SystemColors.InactiveCaption;
                    tiles[k].FlatAppearance.BorderSize = 0;
                    tiles[k].FlatStyle = System.Windows.Forms.FlatStyle.Flat;
                    tiles[k].ForeColor = System.Drawing.SystemColors.ActiveCaptionText;
                    tiles[k].Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                            | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right)));
                    tiles[k].AutoSize = true;
                    tiles[k].Location = new System.Drawing.Point(1, 1);
                    tiles[k].Name = "tiles" + k;
                    tiles[k].Size = new System.Drawing.Size(75, 23);
                    tiles[k].Text = (board[i,j] == 0 ? "" : board[i,j] + "");
                    tiles[k].Font = new System.Drawing.Font("Microsoft Sans Serif", 20F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0)));
                    tiles[k].UseVisualStyleBackColor = false;

                    ///
                    tablero.Controls.Add(tiles[k]);

                    k++;
                }

            tablero.Refresh();
            tablero.Show();
        }

        public void updateTiles(short[,] board)
        {
            int size = board.GetLength(0);
            int k = 0;

            for (int i = 0; i < size; i++)
                for (int j = 0; j < size; j++)
                {
                    tiles[k].Text = (board[i, j] == 0 ? "" : board[i, j] + "");
                    k++;
                }
        }

        private void btnpause_Click(object sender, EventArgs e)
        {
            controller.Pause();
        }

        private void btnStart_Click(object sender, EventArgs e)
        {
            if (controller.IsRunning())
                controller.Stop();
            else
            {
                if (controller.IsStopped())
                    selectBehavior();

                controller.Start();
            }
        }

        private void cmbModel_SelectedIndexChanged(object sender, EventArgs e)
        {
            selectBehavior();
        }

        private void cmbSize_SelectedIndexChanged(object sender, EventArgs e)
        {
            selectBehavior();
        }

        private void btnScramble_Click(object sender, EventArgs e)
        {
            selectBehavior();
        }

        #endregion

        private void btnUndo_Click(object sender, EventArgs e)
        {
            controller.UnDoMoveCell();
        }

        private void tbSpeed_Scroll(object sender, EventArgs e)
        {
            controller.SetSleepInterval(tbSpeed.Value);
        }
     }
}